package de.fzi.kasma.learner.genetic;

import java.util.Set;

import de.fzi.kasma.learner.path.PathEdge;
import de.fzi.kasma.learner.path.PathGraph;
import ec.EvolutionState;
import ec.util.Parameter;
import ec.vector.VectorIndividual;

public class RLIndividual extends VectorIndividual{

	public PathGraph[] clauses;
	public int m_genomeLen;
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -5562240052802487692L;

	@Override
	public boolean equals(Object ind) {
		// TODO Auto-generated method stub
		if (!getClass().equals(ind.getClass()))  // not the same class, I'm conservative that way
	            return false;

	    RLIndividual other = (RLIndividual)ind;
	        if (clauses.length != other.clauses.length) return false;
	        for(int x=0;x<clauses.length;x++)
	            if (!clauses[x].equals(other.clauses[x])) return false; // TODO: equals fcn at PathGraph need to be implemented
	        return true;
	}

	@Override
	public int hashCode() {
		// 
		 int hash = this.getClass().hashCode();
	        for(int x=0;x<clauses.length;x++)
	            // rotate hash and XOR
	            hash =
	                (hash << 1 | hash >>> 31 ) ^ clauses[x].hashCode();
	        return hash;
	}

	@Override
	public Parameter defaultBase() {
		// TODO Auto-generated method stub
		return RLDefaults.base().push(P_INDIVIDUAL);
	}

	@Override
	public Object clone() {
	    RLIndividual myobj = (RLIndividual) (super.clone()); 
        myobj.clauses= new PathGraph[clauses.length];
        for(int x=0;x<clauses.length;x++) 
            myobj.clauses[x] = (PathGraph)(clauses[x].clone()); // TODO: Implement clone function at PathGraph
        myobj.fitness = fitness;
        return myobj;
    }

	@Override
	public void setup(EvolutionState state, Parameter base) {
		// TODO Auto-generated method stub
		super.setup(state, base);
		
		this.evaluated=false;
		
	}

	@Override
	public void reset(EvolutionState state, int thread) {
		// 
//		PathGraph[] temp=new PathGraph[m_genomeLen];
//		for(int i=0;i<clauses.length;i++)
//		{
//			temp[i]=(PathGraph)clauses[i].clone();			
//		}
//
//		for(int i=clauses.length;i<m_genomeLen;i++)
//		{
//			temp[i]=new PathGraph(); // TODO: initialize new genes with default pathgraphs			
//		}
//		
//		clauses=temp;
		
	}

	@Override
	public long genomeLength() {
		// TODO Auto-generated method stub
		return m_genomeLen;
	}

	@Override
	public void setGenomeLength(int len) {
		// TODO Auto-generated method stub
		this.m_genomeLen=len;
	}

	public void postprocessIndividual(EvolutionState state, int thread) {
		
//		Set<PathEdge> edgeSet = clauses[0].edgeSet();
//
//		for(PathEdge e : edgeSet){
//		System.out.println("Edges :"+e.getProperty().toString());
//		}
	}

	public void preprocessIndividual(EvolutionState state, int thread) {
		// TODO Auto-generated method stub
		
	}


	public RLIndividual[] splitIntoTwo(EvolutionState state, int thread,
			RLIndividual[] twoIndividuals, float crossProbability) {
		
	       for( PathGraph pg : clauses )
	            if (state.random[thread].nextBoolean(crossProbability)){
	            	if(twoIndividuals[0].clauses != null){
	            		int newLength = twoIndividuals[0].clauses.length +1;
	            		PathGraph[] newClauses = new PathGraph[newLength];
	            		System.arraycopy(twoIndividuals[0].clauses, 0, newClauses, 0, twoIndividuals[0].clauses.length);
	            		twoIndividuals[0].clauses = newClauses;
	            		twoIndividuals[0].clauses[newLength-1] = new PathGraph();
	            		twoIndividuals[0].clauses[newLength-1] = pg;
	            	}else{

	            		twoIndividuals[0].clauses = new PathGraph[1];
	            		twoIndividuals[0].clauses[0] = new PathGraph();
	            		twoIndividuals[0].clauses[0] = pg;
	            	}
	            	
	            } else{

	            	if(twoIndividuals[1].clauses != null){
	            		int newLength = twoIndividuals[1].clauses.length +1;
	            		PathGraph[] newClauses = new PathGraph[newLength];
	            		System.arraycopy(twoIndividuals[1].clauses, 0, newClauses, 0, twoIndividuals[1].clauses.length);
	            		twoIndividuals[1].clauses = newClauses;
	            		twoIndividuals[1].clauses[newLength-1] = new PathGraph();
	            		twoIndividuals[1].clauses[newLength-1] = pg;
	            		
	            	}else{

	            		twoIndividuals[1].clauses = new PathGraph[1];
	            		twoIndividuals[1].clauses[0] = new PathGraph();
	            		twoIndividuals[1].clauses[0] = pg;
	            	}
	            }
	        return twoIndividuals;
	}


	public void copyNoClone(RLIndividual other) {

            {
                this.clauses = other.clauses;
                this.m_genomeLen = other.m_genomeLen;
    		
            }
     }
    public void printIndividualForHumans(final EvolutionState state,
            final int log, 
            final int verbosity)

            {
    	
//    		super.printIndividualForHumans(state, log, verbosity);
    		
                state.output.println("The best clauses: ", verbosity, log);
                for(int i =0; i<clauses.length; i++){
                	PathGraph pg = clauses[i];

                	for(PathEdge e : clauses[0].edgeSet()){
                    	state.output.println(e.getSource().getLabel().toString()+" "+e.getProperty()+" "+e.getTarget()+" ; ", verbosity, log);

                	}

                }
                state.output.println("The prediction accuracy: "+fitness.fitness(), verbosity, log);
//
                
                
//                fitness.printFitnessForHumans(state,log,verbosity);
//            state.output.println( genotypeToStringForHumans(), verbosity, log );
            }
	
}
